home *** CD-ROM | disk | FTP | other *** search
/ Mac Mania 6 / MacMania 6.toast / / Tools&Utilities / EnterAct Stuff / Indent project / Indent Source / comments.c < prev    next >
Encoding:
C/C++ Source or Header  |  1997-01-24  |  16.7 KB  |  645 lines  |  [TEXT/MPS ]

  1. /* Copyright (c) 1993,1994, Joseph Arceneaux.  All rights reserved.
  2.  
  3.    This file is subject to the terms of the GNU General Public License as
  4.    published by the Free Software Foundation.  A copy of this license is
  5.    included with this software distribution in the file COPYING.  If you
  6.    do not have a copy, you may obtain a copy by writing to the Free
  7.    Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
  8.  
  9.    This software is distributed in the hope that it will be useful,
  10.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  11.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12.    GNU General Public License for more details. */
  13.  
  14. #include <string.h>
  15.  
  16. #include "sys.h"
  17. #include "indent.h"
  18.  
  19. /* Check the limits of the comment buffer, and expand as neccessary. */
  20.  
  21. #define CHECK_COM_SIZE \
  22.     if (e_com >= l_com) \
  23.           { \
  24.         size_t nsize = l_com-s_com+400; \
  25.         combuf = (char *) xrealloc (combuf, nsize,"CHECK_COM_SIZE"); \
  26.         e_com = combuf + (e_com-s_com) + 1; \
  27.         l_com = combuf + nsize - 5; \
  28.         s_com = combuf + 1; \
  29.       }
  30.  
  31. /* The number of comments handled so far. */
  32. int out_coms;
  33.  
  34. // Functions from other files:
  35. extern int inc_pstack (void);
  36. extern INLINE int current_column (void);
  37. extern INLINE void fill_buffer (void);
  38. extern void dump_line (void);
  39. extern INLINE int count_columns (int column, char *bp);
  40. extern INLINE int compute_code_target (void);
  41. extern INLINE int compute_label_target (void);
  42.  
  43.  
  44. // Functions defined here:
  45. void print_comment (void);
  46.  
  47.  
  48. /* Output a comment.  `buf_ptr' is pointing to the character after
  49.    the beginning comment delimiter when this is called.  This handles
  50.    both C and C++ comments.
  51.  
  52.    As far as indent is concerned, there are basically two types
  53.    of comments -- those on lines by themselves and those which are
  54.    on lines with other code.  Variables (and the options specifying them)
  55.    affecting the printing of comments are:
  56.  
  57.    `format_comments'                ("fca"):  Ignore newlines in the
  58.        comment and perform filling up to `max_col'.  Double newlines
  59.        indicate paragraph breaks.
  60.  
  61.    `format_col1_comments'           ("fc1"):  Format comments which
  62.        begin in column 1.
  63.  
  64.    `unindent_displace'              ("d"):  The hanging indentation for
  65.        comments which do not appear to the right of code.
  66.  
  67.    `comment_delimiter_on_blankline' ("cdb"):  If set, place the comment
  68.        delimiters on lines by themselves.  This only affects comments
  69.        which are not to the right of code.
  70.  
  71.    `com_ind'                        ("c"):  The column in which to begin
  72.        comments that are to the right of code.
  73.  
  74.    `decl_com_ind'                   ("cd"):  The column in which to begin
  75.        comments that are to the right of declarations.
  76.  
  77.    `else_endif_col'                 ("cp"):  The column in which to begin
  78.        comments to the right of preprocessor directives.
  79.  
  80.    `star_comment_cont'              ("sc"):  Place a star ('*') to the
  81.        left of the comment body.
  82.  
  83.    `comment_max_col'                ("lc"): The length of a comment line.
  84.        Formatted comments which extend past this column will be continued on
  85.        the following line.  If this option is not specified, `max_col' is
  86.        used.
  87.  
  88.    `max_col'                        ("l"):  The length of a line.
  89.  
  90.    */
  91.  
  92. void
  93. print_comment ()
  94. {
  95.   register int column, format;
  96.   enum codes comment_type;
  97.  
  98.   int start_column, save_length, found_column;
  99.   int first_comment_line, right_margin;
  100.   int boxed_comment = 0, stars, blankline_delims, paragraph_break,
  101.       merge_blank_comment_lines;
  102.   char *line_break_ptr = 0;
  103.   char *save_ptr = 0;
  104.   char *text_on_line = 0;
  105.   char *start_delim, *end_delim;
  106.  
  107.   char *line_preamble;
  108.   int line_preamble_length, visible_preamble;
  109.  
  110.   /* Increment the parser stack, as we will store some things
  111.      there for dump_line to use. */
  112.   inc_pstack ();
  113.  
  114.   /* Have to do it this way because this piece of shit program doesn't
  115.      always place the last token code on the stack. */
  116.   if (*(token + 1) == '/')
  117.     comment_type = cplus_comment;
  118.   else
  119.     comment_type = comment;
  120.  
  121.   /* First, decide what kind of comment this is: C++, C, or boxed C.
  122.      Even if this appears to be a normal C comment, we may change our
  123.      minds if we find a star in the right column of the second line,
  124.      in which case that's a boxed comment too. */
  125.   if (comment_type == cplus_comment)
  126.     {
  127.       start_delim = "//";
  128.       line_preamble = "// ";
  129.       line_preamble_length = 3;
  130.       visible_preamble = 1;
  131.       boxed_comment = 0;
  132.       stars = 0;
  133.       blankline_delims = 0;
  134.     }
  135.   else if (*buf_ptr == '*' || *buf_ptr == '-'
  136.        || *buf_ptr == '=' || *buf_ptr == '_')
  137.     /* Boxed comment */
  138.     {
  139.       found_column = start_column = current_column () - 2;
  140.       parser_state_tos->com_col = found_column;
  141.       parser_state_tos->box_com = boxed_comment;
  142.  
  143.       *e_com++ = '/';
  144.       *e_com++ = '*';
  145.       while (1)
  146.     {
  147.       do
  148.         *e_com++ = *buf_ptr++;
  149.       while (*buf_ptr != '*' && buf_ptr < buf_end);
  150.  
  151.       if (*buf_ptr == '*' && *(buf_ptr + 1) == '/')
  152.         {
  153.           if (buf_ptr == buf_end)
  154.         fill_buffer ();
  155.           buf_ptr += 2;
  156.  
  157.           *e_com++ = '*';
  158.           *e_com++ = '/';
  159.           *e_com = '\0';
  160.           parser_state_tos->tos--;
  161.           parser_state_tos->com_col = 1;
  162.           return;
  163.         }
  164.  
  165.       if (buf_ptr == buf_end)
  166.         {
  167.           if (*(buf_ptr - 1) == EOL)
  168.         {
  169.           *(--e_com) = '\0';
  170.           dump_line ();
  171.           parser_state_tos->com_col = 1;
  172.         }
  173.  
  174.           fill_buffer ();
  175.           if (had_eof)
  176.         {
  177.           *e_com++ = '\0';
  178.           parser_state_tos->tos--;
  179.           parser_state_tos->com_col = start_column;
  180.           return;
  181.         }
  182.         }
  183.     }
  184.  
  185. #if 0
  186.       start_delim = "/*";
  187.       end_delim = "*/";
  188.       line_preamble = " ";
  189.       line_preamble_length = 1;
  190.       visible_preamble = 0;
  191.       boxed_comment = 1;
  192.       stars = 0;
  193.       blankline_delims = 0;
  194. #endif
  195.     }
  196.   else
  197.     {
  198.       start_delim = "/*";
  199.       end_delim = "*/";
  200.       line_preamble = 0;
  201.       line_preamble_length = 0;
  202.       visible_preamble = 0;
  203.       boxed_comment = 0;
  204.       stars = star_comment_cont;
  205.       blankline_delims = comment_delimiter_on_blankline;
  206.     }
  207.  
  208.   paragraph_break = 0;
  209.   merge_blank_comment_lines = 0;
  210.   first_comment_line = com_lines;
  211.   right_margin = comment_max_col;
  212.  
  213.   /* Now, compute the correct indentation for this comment
  214.      and whether or not it should be formatted. */
  215.   found_column = current_column () - 2;
  216.   if (boxed_comment)
  217.     {
  218.       start_column = found_column;
  219.       format = 0;
  220.       blankline_delims = 0;
  221.     }
  222.   else
  223.     {
  224.       /* First handle comments which begin the line. */
  225.       if ((s_lab == e_lab) && (s_code == e_code))
  226.     {
  227.       /* This is a top-level comment, not within some code. */
  228.       if (parser_state_tos->ind_level <= 0)
  229.         {
  230.           if (parser_state_tos->col_1)
  231.         {
  232.           format = format_col1_comments;
  233.           start_column = 1;
  234.         }
  235.           else
  236.         {
  237.           format = format_comments;
  238.           start_column = found_column;
  239.         }
  240.         }
  241.       /* Here for comments starting a line, in the middle of code. */
  242.       else
  243.         {
  244.           if (parser_state_tos->col_1)
  245.         {
  246.           format = format_col1_comments;
  247.           start_column = 1;
  248.         }
  249.           else
  250.         {
  251.           format = format_comments;
  252.           start_column = (parser_state_tos->ind_level
  253.                   - unindent_displace + 1);
  254.           if (start_column < 0)
  255.             start_column = 1;
  256.         }
  257.         }
  258.     }
  259.       else
  260.     /* This comment follows code of some sort. */
  261.     {
  262.       int target;
  263.  
  264.       /* First, compute where the comment SHOULD go. */
  265.       if (parser_state_tos->decl_on_line)
  266.         target = decl_com_ind;
  267.       else if (else_or_endif)
  268.         target = else_endif_col;
  269.       else
  270.         target = com_ind;
  271.  
  272.       /* Now determine if the code on the line is short enough
  273.          to allow the comment to begin where it should. */
  274.       if (s_code != e_code)
  275.         start_column = count_columns (compute_code_target (), s_code);
  276.       else
  277.         /* s_lab != e_lab : there is a label here. */
  278.         start_column = count_columns (compute_label_target (), s_lab);
  279.  
  280.       if (start_column < target)
  281.         start_column = target;
  282.       else
  283.         {
  284.           /* If the too-long code is a pre-processor command,
  285.          start the comment 1 space afterwards, otherwise
  286.          start at the next tab mark. */
  287.           if (else_or_endif)
  288.         {
  289.           start_column++;
  290.           else_or_endif = false;
  291.         }
  292.           else
  293.         start_column += (tabsize - (start_column % tabsize) + 1);
  294.         }
  295.  
  296.       format = format_comments;
  297.     }
  298.     }
  299.  
  300.   if (! line_preamble)
  301.     {
  302.       line_preamble_length = 3;
  303.       if (stars)
  304.     {
  305.       line_preamble = " * ";
  306.       visible_preamble = 1;
  307.     }
  308.       else
  309.     {
  310.       line_preamble = "   ";
  311.       visible_preamble = 0;
  312.     }
  313.     }
  314.  
  315.   /* These are the parser stack variables used to communicate
  316.      formatting information to dump_line (). */
  317.   parser_state_tos->com_col = start_column;
  318.   parser_state_tos->box_com = boxed_comment;
  319.   if (boxed_comment)
  320.     {                /* Why is this here?  Could these vars have
  321.                    been reset after the boxed_comment code
  322.                    above?  Check this out.  */
  323.       stars = 0;
  324.       blankline_delims = 0;
  325.     }
  326.  
  327.   /* Output the beginning comment delimiter.  They are both two
  328.      characters long. */
  329.   *e_com++ = *start_delim;
  330.   *e_com++ = *(start_delim + 1);
  331.   column = start_column + 2;
  332.  
  333.   /* If the user specified -cdb, put the delimiter on one line. */
  334.   if (blankline_delims)
  335.     {
  336.       char *p = buf_ptr;
  337.  
  338.       *e_com = '\0';
  339.       dump_line ();
  340.  
  341.       /* Check if the delimiter was already on a line by itself,
  342.      and skip whitespace if formating. */
  343.       while (*p == ' ' || *p == TAB)
  344.     p++;
  345.       if (*p == EOL)
  346.     buf_ptr = p + 1;
  347.       else if (format)
  348.     buf_ptr = p;
  349.       if (buf_ptr >= buf_end)
  350.     fill_buffer ();
  351.  
  352.       column = start_column;
  353.       goto begin_line;
  354.     }
  355.   else if (format)
  356.     {
  357.       *e_com++ = ' ';
  358.       column = start_column + 3;
  359.       while (*buf_ptr == ' ' || *buf_ptr == TAB)
  360.     if (++buf_ptr >= buf_end)
  361.       fill_buffer ();
  362.     }
  363.  
  364.   /* Iterate through the lines of the comment */
  365.   while (! had_eof)
  366.     {
  367.       /* Iterate through the characters on one line */
  368.       while (! had_eof)
  369.     {
  370.       CHECK_COM_SIZE;
  371.  
  372.       switch (*buf_ptr)
  373.         {
  374.         case ' ':
  375.         case TAB:
  376.           /* If formatting, and previous break marker is
  377.              nonexistant, or before text on line, reset
  378.          it to here. */
  379.           if (format && line_break_ptr < text_on_line)
  380.         line_break_ptr = e_com;
  381.  
  382.           if (*buf_ptr == ' ')
  383.         {
  384.           *e_com++ = ' ';
  385.           column++;
  386.         }
  387.           else
  388.         {
  389.           /* Convert the tab to the appropriate number of spaces,
  390.              based on the column we found the comment in, not
  391.              the one we're printing in. */
  392.           int tab_width
  393.             = (tabsize - ((column + found_column - start_column - 1)
  394.                   % tabsize));
  395.           column += tab_width;
  396.           while (tab_width--)
  397.             *e_com++ = ' ';
  398.         }
  399.           break;
  400.  
  401.  
  402.         case EOL:
  403.           /* We may be at the end of a C++ comment */
  404.           if (comment_type == cplus_comment)
  405.         {
  406.           dump_line ();
  407.           buf_ptr++;
  408.           if (buf_ptr >= buf_end)
  409.             fill_buffer ();
  410.  
  411.           parser_state_tos->tos--;
  412.           parser_state_tos->com_col = start_column;
  413.           return;
  414.         }
  415.  
  416.           if (format)
  417.         {
  418.           /* Newline and null are the two characters which
  419.              end an input line, so check here if we need to
  420.              get the next line. */
  421.           buf_ptr++;
  422.           if (buf_ptr >= buf_end)
  423.             fill_buffer ();
  424.  
  425.           /* If this is "\n\n", it's a paragraph break. */
  426.           if (*buf_ptr == EOL || ! text_on_line)
  427.             {
  428.               paragraph_break = 1;
  429.               goto end_line;
  430.             }
  431.  
  432.           /* This is a single newline.  Transform it, and any
  433.              following whitespace into a single blank. */
  434.           line_break_ptr = e_com;
  435.           *e_com++ = ' ';
  436.           column++;
  437.           while (*buf_ptr == TAB || *buf_ptr == ' ')
  438.             if (buf_ptr++ >= buf_end)
  439.               fill_buffer ();
  440.           continue;
  441.         }
  442.           else
  443.         /* We are printing this line "as is", so output it
  444.            and continue on to the next line. */
  445.         goto end_line;
  446.           break;
  447.  
  448.         case '*':
  449.           /* Check if we've reached the end of the comment. */
  450.           if (comment_type == comment)
  451.         {
  452.           if (*(buf_ptr + 1) == '/')
  453.             {
  454.               /* If it's not a boxed comment, put some whitespace
  455.                  before the ending delimiter.  Otherwise, simply
  456.              insert the delimiter. */
  457.               if (! boxed_comment)
  458.             {
  459.               if (text_on_line)
  460.                 {
  461.                   if (blankline_delims)
  462.                 {
  463.                   *e_com = '\0';
  464.                   dump_line ();
  465.                   *e_com++ = ' ';
  466.                 }
  467.                   else
  468.                 /* Insert space before closing delim */
  469.                 if (*(e_com - 1) != ' '&& *(e_com - 1) != TAB)
  470.                   *e_com++ = ' ';
  471.                 }
  472.               /* If no text on line, then line is completely empty
  473.                   or starts with preamble, or is beginning of
  474.                   comment and starts with beginning delimiter. */
  475.               else if (s_com == e_com
  476.                    || *s_com != '/')
  477.                 {
  478.                   e_com = s_com;
  479.                   *e_com++ = ' ';
  480.                 }
  481.               else
  482.                 /* This is case of first comment line.  Test
  483.                    with:
  484.                      if (first_comment_line != com_lines)
  485.                    abort(); */
  486.                 if (*(e_com - 1) != ' ' && *(e_com - 1) != TAB)
  487.                   *e_com++ = ' ';
  488.             }
  489.  
  490.               /* Now insert the ending delimiter */
  491.               *e_com++ = '*';
  492.               *e_com++ = '/';
  493.               *e_com = '\0';
  494.  
  495.               /* Skip any whitespace following the comment.  If
  496.              there is only whitespace after it, print the line. */
  497.               /* NOTE:  We're not printing the line: TRY IT! */
  498.               buf_ptr += 2;
  499.               while (*buf_ptr == ' ' || *buf_ptr == TAB)
  500.             buf_ptr++;
  501.               if (buf_ptr >= buf_end)
  502.               fill_buffer ();
  503.  
  504.               parser_state_tos->tos--;
  505.               parser_state_tos->com_col = start_column;
  506.               return;
  507.             }
  508.  
  509.           /* If this star is on the second line of the
  510.              comment in the same column as the star of the
  511.              beginning delimiter, then consider it
  512.              a boxed comment. */
  513.           if (first_comment_line == com_lines - 1
  514.               && e_com == s_com + line_preamble_length
  515.               && current_column () == found_column + 1)
  516.             {
  517.               line_preamble = " ";
  518.               line_preamble_length = 1;
  519.               boxed_comment = 1;
  520.               format = 0;
  521.               blankline_delims = 0;
  522.               *s_com = ' ';
  523.               *(s_com + 1) = '*';
  524.               e_com = s_com + 2;
  525.               column++;
  526.               break;
  527.             }
  528.         }
  529.           /* If it was not the end of the comment, drop through
  530.              and insert the star on the line. */
  531.  
  532.         default:
  533.           /* Some textual character. */
  534.           text_on_line = e_com;
  535.           *e_com++ = *buf_ptr;
  536.           column++;
  537.           break;
  538.         }
  539.  
  540.  
  541.       /* If we are formatting, check that we haven't exceeded the
  542.          line length.  If we haven't set line_break_ptr, keep going. */
  543.       if (format && column > right_margin && line_break_ptr)
  544.         {
  545.           if (line_break_ptr < e_com - 1)
  546.         {
  547.           *line_break_ptr = '\0';
  548.           save_ptr = line_break_ptr + 1;
  549.           save_length = e_com - save_ptr;
  550.           e_com = line_break_ptr;
  551.  
  552.           /* If we had to go past `right_margin' to print stuff out,
  553.              extend `right_margin' out to this point. */
  554.           if ((column - save_length) > right_margin)
  555.             right_margin = column - save_length;
  556.         }
  557.           else
  558.         *e_com = '\0';
  559.           goto end_line;
  560.         }
  561.  
  562.       buf_ptr++;
  563.       if (buf_ptr == buf_end)
  564.         fill_buffer ();
  565.     }
  566.  
  567.  
  568.     end_line:
  569.       /* Compress pure whitespace lines into newlines. */
  570.       if (! text_on_line
  571.       && ! visible_preamble
  572.       && ! (first_comment_line == com_lines))
  573.     e_com = s_com;
  574.       *e_com = '\0';
  575.       dump_line ();
  576.  
  577.       /* If formatting (paragraph_break is only used for formatted
  578.      comments) and user wants blank lines merged, kill all white
  579.      space after the "\n\n" indicating a paragraph break. */
  580.       if (paragraph_break)
  581.     {
  582.       if (merge_blank_comment_lines)
  583.         while (*buf_ptr == EOL || *buf_ptr == ' ' || *buf_ptr == TAB)
  584.           if (++buf_ptr >= buf_end)
  585.         fill_buffer ();
  586.       paragraph_break = 0;
  587.     }
  588.       else
  589.     {
  590.       /* If it was a paragraph break (`if' clause), we scanned ahead
  591.          one character.  So, here in the `else' clause, advance buf_ptr. */
  592.       buf_ptr++;
  593.       if (buf_ptr >= buf_end)
  594.         fill_buffer ();
  595.     }
  596.  
  597.     begin_line:
  598.       if (had_eof)
  599.     break;
  600.  
  601.       /* Indent the line properly.  If it's a boxed comment, align with
  602.      the '*' in the beginning slash-star and start inserting there.
  603.      Otherwise, insert blanks for alignment, or a star if the
  604.      user specified -sc. */
  605.       if (line_preamble)
  606.     {
  607.       memcpy (e_com, line_preamble, line_preamble_length);
  608.       e_com += line_preamble_length;
  609.       column = start_column + line_preamble_length;
  610.     }
  611.       else
  612.     column = start_column;
  613.       line_break_ptr = 0;
  614.  
  615.       /* If we have broken the line before the end for formatting,
  616.          copy the text after the break onto the beginning of this
  617.      new comment line. */
  618.       if (save_ptr)
  619.     {
  620.       while ((*save_ptr == ' ' || *save_ptr == TAB) && save_length)
  621.         {
  622.           save_ptr++;
  623.           save_length--;
  624.         }
  625.       memcpy (e_com, save_ptr, save_length);
  626.       text_on_line = e_com;
  627.       e_com += save_length;
  628.       /* We only break if formatting, in which cases there
  629.          are no tabs, only spaces.*/
  630.       column += save_length;
  631.       save_ptr = 0;
  632.     }
  633.       else
  634.     {
  635.       while (*buf_ptr == ' ' || *buf_ptr == TAB)
  636.         if (++buf_ptr >= buf_end)
  637.           fill_buffer ();
  638.       text_on_line = 0;
  639.     }
  640.     }
  641.  
  642.   parser_state_tos->tos--;
  643.   parser_state_tos->com_col = start_column;
  644. }
  645.